package com.hzy.utils.pay;

import com.alibaba.fastjson.JSON;
import com.hzy.constant.ConfigConstants;
import com.hzy.utils.HttpUtils;
import okhttp3.*;
import org.jdom2.JDOMException;

import java.io.IOException;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.util.*;


/**
 * Created by admin on 2017/12/5.
 */
public class WeixinUtils {
    public static void main(String[] args) {
        try {
            System.out.println(getOrderInfo(new BigDecimal(1), "测试", CommonPayUtil.getOutTradeNo(1),  "123.123.123.13"));
        } catch (IOException | JDOMException e) {
            e.printStackTrace();
        }
    }

    public static String getOrderInfo(BigDecimal totalFee, String body, String outTradeNo, String remoteIp) throws IOException, JDOMException {
        //请求参数
        TreeMap<String, String> arrays = new TreeMap<>();
        arrays.put("appid", ConfigConstants.WEIXIN_APPID);
        arrays.put("mch_id", ConfigConstants.WEIXIN_MCHID);
        arrays.put("body", body);
        arrays.put("nonce_str", getNonceStr());
        arrays.put("notify_url", ConfigConstants.WEIXIN_NOTIFYURL);
        arrays.put("out_trade_no", outTradeNo);
        arrays.put("spbill_create_ip", remoteIp);
        arrays.put("total_fee", String.valueOf(totalFee));
//        arrays.put("total_fee", String.valueOf(new BigDecimal(1)));
        arrays.put("trade_type", ConfigConstants.WEIXIN_TRADE_TYPE);
        // 签名
        String sign = createSign(arrays);
        // 拼接请求参数
        arrays.put("sign", sign);
        // 转换请求参数为XML
        String xml = CommonPayUtil.parseXML(arrays);
        System.out.println(xml);
        // 请求预付单id
        OkHttpClient client = new OkHttpClient();
        Request requestOkHttp = new Request.Builder().url(ConfigConstants.WEIXIN_URL)
                .post(RequestBody.create(MediaType.parse("application/xml"), xml)).build();
        ResponseBody responseBody = client.newCall(requestOkHttp).execute().body();
        if (responseBody == null) {
            //System.out.println("no body...");
            return ConfigConstants.ERROR_LOW;
        }
        String result = responseBody.string();
        //结果集
        SortedMap<String, String> resultMap = CommonPayUtil.parseMap(result);
        System.out.println("统一下单接口返回结果" + result);
        //取得预付单id
        if (resultMap.containsKey(ConfigConstants.WEIXIN_RESULT_CODE) && resultMap.containsKey(ConfigConstants.WEIXIN_RETURN_CODE)
                && resultMap.containsKey(ConfigConstants.WEIXIN_PREPAY_ID)) {
            String returnCode = resultMap.get(ConfigConstants.WEIXIN_RETURN_CODE);
            String resultCode = resultMap.get(ConfigConstants.WEIXIN_RESULT_CODE);
            if ("SUCCESS".equals(resultCode) && "SUCCESS".equals(returnCode)) {
                //取得prepare_id
                String prepayId = resultMap.get(ConfigConstants.WEIXIN_PREPAY_ID);
                //System.out.println();
                //System.out.println(prepayId);
                //System.out.println();
                SortedMap<String, String> orderInfoMap = new TreeMap<>();
                orderInfoMap.put("appid", ConfigConstants.WEIXIN_APPID);
                orderInfoMap.put("partnerid", ConfigConstants.WEIXIN_MCHID);
                orderInfoMap.put("prepayid", prepayId);
                orderInfoMap.put("noncestr", getNonceStr());
                orderInfoMap.put("package", "Sign=WXPay");
                orderInfoMap.put("timestamp", getTimestamp());
                String sign2 = createSign(orderInfoMap);
                orderInfoMap.put("sign", sign2);
                return JSON.toJSONString(orderInfoMap);
            } else {
                throw new IOException("no result..");
            }
        } else {
            throw new IOException("no result..");
        }
    }

    private static String getTimestamp() {
        return String.valueOf(System.currentTimeMillis()).substring(0, 10);
    }

    private static String getNonceStr() {
        UUID uuid = UUID.randomUUID();
        return uuid.toString().substring(5, 25);
    }


    private static String createSign(SortedMap<String, String> parameters) {
        //参数过滤
        SortedMap<String, String> stringSortedMap = paraFilter(parameters);
        //创建拼接字符串对象
        StringBuilder sb = new StringBuilder();
        //遍历SortedMap
        Set es = stringSortedMap.entrySet();
        for (Object e : es) {
            Map.Entry entry = (Map.Entry) e;
            String k = (String) entry.getKey();
            Object v = entry.getValue();
            if (null != v && !"".equals(v)
                    && !"sign".equals(k) && !"key".equals(k)) {
                //开始拼接字符串
                sb.append(k).append("=").append(v).append("&");
            }
        }
        sb.append("key=").append(ConfigConstants.WEIXIN_APP_SECRET);
        return md5Encode(sb.toString()).toUpperCase();
    }

    private static SortedMap<String, String> paraFilter(SortedMap<String, String> sArray) {
        //构建新的容器用作返回
        SortedMap<String, String> result = new TreeMap<>();
        if (sArray == null || sArray.size() <= 0) {
            return result;
        }
        for (String key : sArray.keySet()) {
            String value = sArray.get(key);
            if (value == null || "".equals(value) || "sign".equalsIgnoreCase(key)
                    || "sign_type".equalsIgnoreCase(key)) {
                continue;
            }
            result.put(key, value);
        }
        return result;
    }

    private static String md5Encode(String origin) {
        //构建返回字符串
        String resultString = null;
        try {
            resultString = origin;
            MessageDigest md = MessageDigest.getInstance("MD5");
            resultString = byteArrayToHexString(md.digest(resultString
                    .getBytes(ConfigConstants.WEIXIN_CHARSET)));
        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return resultString;
    }

    private static String byteArrayToHexString(byte[] b) {
        StringBuilder resultSb = new StringBuilder();
        for (byte b1 : b) {
            resultSb.append(byteToHexString(b1));
        }

        return resultSb.toString();
    }

    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n += 256;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return HEX_DIGITS[d1] + HEX_DIGITS[d2];
    }

    private static final String[] HEX_DIGITS = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};



    // -------------------------------------------------------- 商品订单支付 --------------------------------------------------------

    /**
     * 外卖平台微信支付
     * @param totalFee
     * @param body
     * @param outTradeNo
     * @param remoteIp
     * @return
     * @throws IOException
     * @throws JDOMException
     */
    public static String getGoodsOrderInfo(BigDecimal totalFee, String body, String outTradeNo, String remoteIp) throws IOException, JDOMException {
        //请求参数
        TreeMap<String, String> arrays = new TreeMap<>();
        arrays.put("appid", ConfigConstants.WEIXIN_APPID);
        arrays.put("body", body);
        arrays.put("mch_id", ConfigConstants.WEIXIN_MCHID);
        arrays.put("nonce_str", getNonceStr());
        arrays.put("notify_url", ConfigConstants.WEIXIN_GOODS_NOTIFY_URL);
        arrays.put("out_trade_no", outTradeNo);
        arrays.put("spbill_create_ip", remoteIp);
        arrays.put("total_fee", String.valueOf(totalFee));
        arrays.put("trade_type", ConfigConstants.WEIXIN_TRADE_TYPE);
        // 签名
        String sign = createSign(arrays);
        // 拼接请求参数
        arrays.put("sign", sign);
        // 转换请求参数为XML
        String xml = CommonPayUtil.parseXML(arrays);
        //System.out.println(xml);
        // 请求预付单id
        OkHttpClient client = new OkHttpClient();
        Request requestOkHttp = new Request.Builder().url(ConfigConstants.WEIXIN_URL)
                .post(RequestBody.create(MediaType.parse("application/xml"), xml)).build();
        ResponseBody responseBody = client.newCall(requestOkHttp).execute().body();
        if (responseBody == null) {
            //System.out.println("no body...");
            return ConfigConstants.ERROR_LOW;
        }
        String result = responseBody.string();
        //结果集
        SortedMap<String, String> resultMap = CommonPayUtil.parseMap(result);
        System.out.println("统一下单接口返回结果" + result);
        //取得预付单id
        if (resultMap.containsKey(ConfigConstants.WEIXIN_RESULT_CODE) && resultMap.containsKey(ConfigConstants.WEIXIN_RETURN_CODE)
                && resultMap.containsKey(ConfigConstants.WEIXIN_PREPAY_ID)) {
            String returnCode = resultMap.get(ConfigConstants.WEIXIN_RETURN_CODE);
            String resultCode = resultMap.get(ConfigConstants.WEIXIN_RESULT_CODE);
            if (ConfigConstants.SUCCESS_UP.equals(resultCode) && ConfigConstants.SUCCESS_UP.equals(returnCode)) {
                //取得prepare_id
                String prepayId = resultMap.get(ConfigConstants.WEIXIN_PREPAY_ID);
                //System.out.println();
                //System.out.println(prepayId);
                //System.out.println();
                SortedMap<String, String> orderInfoMap = new TreeMap<>();
                orderInfoMap.put("appid", ConfigConstants.WEIXIN_APPID);
                orderInfoMap.put("partnerid", ConfigConstants.WEIXIN_MCHID);
                orderInfoMap.put("prepayid", prepayId);
                orderInfoMap.put("noncestr", getNonceStr());
                orderInfoMap.put("package", "Sign=WXPay");
                orderInfoMap.put("timestamp", getTimestamp());
                String sign2 = createSign(orderInfoMap);
                orderInfoMap.put("sign", sign2);
                return JSON.toJSONString(orderInfoMap);
            } else {
                throw new IOException("no result..");
            }
        } else {
            throw new IOException("no result..");
        }
    }


    /**
     * 外卖平台微信退款
     * @param totalFee 订单金额
     * @param refundFee 退款金额
     * @param refundDesc 退款原因
     * @param outTradeNo 商户订单号
     * @param outRefundNo 商户退款单号
     * @return
     * @throws IOException
     * @throws JDOMException
     */
    public static boolean getGoodsOrderRefundInfo(BigDecimal totalFee, BigDecimal refundFee, String refundDesc,
                                              String outTradeNo, String outRefundNo) {
        //请求参数
        TreeMap<String, String> arrays = new TreeMap<>();
        arrays.put("appid", ConfigConstants.WEIXIN_APPID);
        arrays.put("mch_id", ConfigConstants.WEIXIN_MCHID);
        arrays.put("nonce_str", getNonceStr());
//        arrays.put("notify_url", "http://www.jiaxiangapp.com/jx/pay/notify/wm/wx_refund");
        arrays.put("out_trade_no", outTradeNo);
        arrays.put("out_refund_no", outRefundNo);
        arrays.put("total_fee", String.valueOf(totalFee));
        arrays.put("refund_fee", String.valueOf(refundFee));
        arrays.put("refund_desc", refundDesc);
        // 签名
        String sign = createSign(arrays);
        // 拼接请求参数
        arrays.put("sign", sign);
        // 转换请求参数为XML
        String xml = CommonPayUtil.parseXML(arrays);

        String xmlStr = HttpUtils.postSSL(ConfigConstants.WEIXIN_REFUND_URL, xml,
                "/home/yfd/1529502291_20190919_cert/apiclient_cert.p12", ConfigConstants.WEIXIN_MCHID);
        System.out.println("申请退款接口返回结果" + xmlStr);


        try {
            SortedMap<String, String> resultMap = CommonPayUtil.parseMap(xmlStr);
            //取得预付单id
            if (resultMap.containsKey(ConfigConstants.WEIXIN_RESULT_CODE) && resultMap.containsKey(ConfigConstants.WEIXIN_RETURN_CODE)) {
                String returnCode = resultMap.get(ConfigConstants.WEIXIN_RETURN_CODE);
                String resultCode = resultMap.get(ConfigConstants.WEIXIN_RESULT_CODE);
                if (ConfigConstants.SUCCESS_UP.equals(resultCode) && ConfigConstants.SUCCESS_UP.equals(returnCode)) {
                    return true;
                } else {
                    System.out.println("微信退款失败》》"+"错误码:"+resultMap.get("return_msg")+"  ;"
                            + "描述:"+resultMap.get("err_code_des"));
                    return false;
                }
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }







}
